local skynet = require "skynet"
local cluster = require "skynet.cluster"
local redisdao = require "redisdao"
local timetool = require "timetool"
local tabletool = require "tabletool"
local queue = require "skynet.queue"
local filelog = require "filelog"
local json = require "cjson"
json.encode_sparse_array(true,1,1)

require "pubenum"

local JackpotMgr = {
    CMD = {},
    jackopt_data = {
        --[[
        --奖池数据
        diamond = 0,
        --]]
        diamond = 0,
    },
    childjackopt_data = {

    },
    getjackpotinfo = {
        --[[
        [childjackpotid] = {
            ----记录只保存5条
            [1] = {
                rid = rid,
                rolename = rolename,
                getnum = getnum,
                money_type = money_type,
                card_type = card_type,
                table_type = table_type,
                get_time = timetool.get_time(),
            }
        }
        --]]
    },
    register_tableaddress = {
        --[[
            [childjackpotid] = {
                [table_code] = table_address,
            }
        --]]
    },
}

local cs_jackopt = queue()

local nodeconf = nil
local nodeconfname = ""
local jackpotgameid = 0

local function updatenodeconf(nodeconfname)
    local result, data = redisdao.query_data(".gmmqredis", "get", nodeconfname)
    if result and data then
        nodeconf = nil
        nodeconf = tabletool.deepcopy(json.decode(data))
    end
end

local function getjackpotconf()
    local nodejackpotconf = nil
    nodejackpotconf = nodeconf.jackoptconf
    if not nodejackpotconf then
        return nil
    else
        return nodejackpotconf
    end
end

local function getchildjackid(childjackopt, base_score)
    local childjackpotid = 0
    for childjackid, childjackpotobj in ipairs(childjackopt) do
        if base_score >= childjackpotobj.basescores[1] and base_score < childjackpotobj.basescores[2] then
            childjackpotid = childjackid
        end
    end
    return childjackpotid
end

local function getjackpotnum(jackpot_id)
    local jackpot = 0   --默认0
    if jackpotgameid == 0 then return jackpot end
    local rid = tonumber(tostring(jackpotgameid)..tostring(jackpot_id))
    local result = cluster.call("datanode", ".router", "select_rk", rid, "rs_jackpot")
    if result[1] == 0 then return jackpot end
    jackpot = result[2][rid]["potnum"]
    return jackpot
end

local function updatejackpotnum(jackpot_id, jackpot_num, value)
    if jackpotgameid == 0 then return false end
    local rid = tonumber(tostring(jackpotgameid)..tostring(jackpot_id))
    local endvalue = jackpot_num + value
    local status = cluster.call("datanode", ".router", "update_rk", rid, "rs_jackpot", 0, { potnum = endvalue})
    if status[1] == 1 and status[2] == true then
        return true
    else
        return false
    end
end

local function update_system_get(gamenode, value)
    local key = (gamenode or skynet.getenv("nodename")) .. "_jackpot_sysget"
    local status,sysget_num = redisdao.query_data(".gmmqredis", "get", key)
    if sysget_num then
        sysget_num = tonumber(sysget_num) or 0
    else
        sysget_num = 0
        redisdao.query_data(".gmmqredis", "set", key, sysget_num)
    end
    local endvalue = sysget_num + value
    local status_sy, result = redisdao.query_data(".gmmqredis", "set", key, endvalue)
    if not status_sy then
        return false
    else
        return true
    end 
end

local function update_jackpot_all(gamenode, value)
    local key = (gamenode or skynet.getenv("nodename")) .. "_jackpot_all"
    local status, allget_num = redisdao.query_data(".gmmqredis", "get", key)
    if allget_num then
        allget_num = tonumber(allget_num) or 0
    else
        allget_num = 0
        redisdao.query_data(".gmmqredis", "set", key, allget_num)
    end
    local endvalue = allget_num + value
    local status_sy, result = redisdao.query_data(".gmmqredis", "set", key, endvalue)
    if not status_sy then
        return false
    else
        return true
    end
end

local function get_jackpot_all(gamenode)
    local key = (gamenode or skynet.getenv("nodename")) .. "_jackpot_all"
    local status, allget_num = redisdao.query_data(".gmmqredis", "get", key)
    if allget_num then
        allget_num = tonumber(allget_num) or 0
    else
        allget_num = 0
        redisdao.query_data(".gmmqredis", "set", key, allget_num)
    end
    return allget_num
end


local function checkgetjackpotinfo(childjackid)
    if not JackpotMgr.getjackpotinfo[childjackid] then return end
    while #JackpotMgr.getjackpotinfo[childjackid] > 5 do
        table.remove(JackpotMgr.getjackpotinfo[childjackid], 1)
    end
end

---gm 增加奖池数量接口
function JackpotMgr.CMD.addjackoptnum(childjackpotid, moneydata, reason)
    if not childjackpotid then return false end
    local childjackdata = JackpotMgr.childjackopt_data[childjackpotid]
    if not childjackdata then return false end
    if moneydata.diamond ~= nil and moneydata.diamond > 0 then
        local beforeadd = childjackdata.diamond
        local status = cs_jackopt(updatejackpotnum, childjackpotid, beforeadd, moneydata.diamond)
        if status == true then
            childjackdata.diamond = childjackdata.diamond + moneydata.diamond
            local logstr = string.format("%d,%d,%d,%d,%d,%d,%s,GM", EDiamondChange.SYS_ADDJACKPOT, 0, childjackpotid, moneydata.diamond, beforeadd,
                    childjackdata.diamond, tostring(timetool.get_time()))
            skynet.send(".jackpotlog", "lua", "jackpot_write_file_redis", logstr, jackpotgameid)
        
            -----通知桌子立即更新
            local registertables =  JackpotMgr.register_tableaddress[childjackpotid]
            if registertables and next(registertables) ~= nil then
                for table_code, table_address in pairs(registertables) do
                    skynet.send(table_address, "lua", "updatejackinfo", JackpotMgr.childjackopt_data[childjackpotid].diamond, EMoneyType.DIAMOND)
                end
            end
        end
    end
    return true
end
---后台取出子奖池数据接口
function JackpotMgr.CMD.deljackoptnum(childjackpotid, moneydata, reason)
    if not childjackpotid then return false end
    local childjackdata = JackpotMgr.childjackopt_data[childjackpotid]
    if not childjackdata then return false end
    if moneydata.diamond ~= nil and moneydata.diamond > 0 then
        if childjackdata.diamond > moneydata.diamond then
            local beforedel = childjackdata.diamond
            local status = cs_jackopt(updatejackpotnum, childjackpotid, beforedel, -moneydata.diamond)
            if status == true then
                childjackdata.diamond = childjackdata.diamond - moneydata.diamond
                local logstr = string.format("%d,%d,%d,%d,%d,%d,%s,GM", EDiamondChange.SYS_GETJACKPOT, 0, childjackpotid, -moneydata.diamond, beforedel,
                    childjackdata.diamond, tostring(timetool.get_time()))
                skynet.send(".jackpotlog", "lua", "jackpot_write_file_redis", logstr, jackpotgameid)
                -----通知桌子立即更新
                local registertables =  JackpotMgr.register_tableaddress[childjackpotid]
                if registertables and next(registertables) ~= nil then
                    for table_code, table_address in pairs(registertables) do
                        skynet.send(table_address, "lua", "updatejackinfo", JackpotMgr.childjackopt_data[childjackpotid].diamond, EMoneyType.DIAMOND)
                    end
                end
            end
        end
    end
    return true
end
---后台gm获得所有奖池现有金额(后台直接查数据库)
function JackpotMgr.CMD.getalljackoptnum()
    local allchildinfo = {}
    for childjackpotid, childjack in ipairs(JackpotMgr.childjackopt_data) do
        table.insert(allchildinfo, {childjackpotid = childjackpotid, diamond = childjack.diamond})
    end
    return allchildinfo
end

---后台gm获得当前抽成比例
function JackpotMgr.CMD.getsysperinfo(chargename)
    local jackpotconf = getjackpotconf()
    if chargename == "chargeconf" then ----获取奖池费比例
        local chargeconf = tabletool.deepcopy(jackpotconf.chargeconf[1])
        local restr = json.encode(chargeconf)
        return restr
    elseif chargename == "system_get" then ---获取手续费比例
        local system_get_conf = { system_get = jackpotconf.system_get, jackopt_get = jackpotconf.jackopt_get}
        local restr = json.encode(system_get_conf)
        return restr
    end
end

---后台调配抽成比例  percent 传小数(0,1)
function JackpotMgr.CMD.changesysper(chargename, percent, play_type)
    if chargename == "chargeconf" then  ----设置奖池费比例
        if nodeconf and nodeconf.jackoptconf and nodeconf.jackoptconf.chargeconf then
            if play_type then
                nodeconf.jackoptconf.chargeconf[1][play_type] = percent
            else
                for play_type, charge in pairs(nodeconf.jackoptconf.chargeconf[1]) do
                    nodeconf.jackoptconf.chargeconf[1][play_type] = percent
                end
            end
        end
    elseif chargename == "system_get" then  ----设置手续费比例
        if nodeconf and nodeconf.jackoptconf then
            nodeconf.jackoptconf.system_get = percent
            nodeconf.jackoptconf.jackopt_get = 1 - percent
        end
    end
    ---重写进redis
    redisdao.query_data(".gmmqredis", "set", nodeconfname, json.encode(nodeconf))
    return true
end

function JackpotMgr.CMD.register_table(base_score, table_code, table_address)
    local jackpotconf = getjackpotconf()
    local childjackid = getchildjackid(jackpotconf.childjackopt, base_score)
    if JackpotMgr.register_tableaddress[childjackid] == nil then 
        JackpotMgr.register_tableaddress[childjackid] = {}
    end
    JackpotMgr.register_tableaddress[childjackid][table_code] = table_address
end

function JackpotMgr.CMD.unregister_table(base_score, table_code)
    local jackpotconf = getjackpotconf()
    local childjackid = getchildjackid(jackpotconf.childjackopt, base_score)
    if JackpotMgr.register_tableaddress[childjackid] == nil then 
        JackpotMgr.register_tableaddress[childjackid] = {}
    end
    JackpotMgr.register_tableaddress[childjackid][table_code] = nil
end

---收取桌子抽水到奖池服务
function JackpotMgr.CMD.updatejackoptnum(alljackoptmoney, comment)
    if not alljackoptmoney or next(alljackoptmoney) == nil then return end
    for index, jackmoney in ipairs(alljackoptmoney) do
        local beforadd = JackpotMgr.jackopt_data.diamond
        if jackmoney.jacktip > 0 then
            JackpotMgr.jackopt_data.diamond = JackpotMgr.jackopt_data.diamond + jackmoney.jacktip
            cs_jackopt(update_jackpot_all, skynet.getenv("nodename"), jackmoney.jacktip)
            local afteradd = JackpotMgr.jackopt_data.diamond
            local logstr = string.format("%d,%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s", EDiamondChange.SUBJACKPOT, jackmoney.rid, -jackmoney.jacktip, 
                jackmoney.beginvalue, jackmoney.endvalue, 0, 0, beforadd, afteradd, comment.table_uuid, comment.start_time, comment.table_tradeid)
            skynet.send(".jackpotlog", "lua", "jackpot_write_file_redis", logstr, jackpotgameid)
        end
    end
end

---奖池开奖
function JackpotMgr.CMD.openjackopt(playersdata, table_code, comment)
    -- body
    local jackpotconf = getjackpotconf()
    if jackpotconf == nil or not jackpotconf.getjackopt or not jackpotconf.childjackopt then return {} end
    if playersdata == nil or #playersdata == 0 then return {} end
    local getjackplayers = {}
    for key, playerdata in ipairs(playersdata) do
        local childjackid = getchildjackid(jackpotconf.childjackopt, playerdata.base_score)
        local childjackdata = JackpotMgr.childjackopt_data[childjackid]
        if childjackdata then
            local getopint =  jackpotconf.getjackopt[tostring(playerdata.card_type)] or jackpotconf.getjackopt[tonumber(playerdata.card_type)]
            if getopint and getopint > 0 and JackpotMgr.childjackopt_data[childjackid].diamond > math.floor(childjackdata.diamond * getopint) then
                local getoptnum = math.floor(childjackdata.diamond * getopint)
                local beforeopen = JackpotMgr.childjackopt_data[childjackid].diamond
                JackpotMgr.childjackopt_data[childjackid].diamond = JackpotMgr.childjackopt_data[childjackid].diamond - getoptnum
                local afteropen = JackpotMgr.childjackopt_data[childjackid].diamond
                local endvalue = playerdata.beginvalue + getoptnum
                local status = cs_jackopt(updatejackpotnum, childjackid, beforeopen, -getoptnum)
                table.insert(getjackplayers, { rid = playerdata.rid, getoptnum = getoptnum, money_type = EMoneyType.DIAMOND, card_type = playerdata.card_type,})
                ----写入记录
                if JackpotMgr.getjackpotinfo[childjackid] == nil then JackpotMgr.getjackpotinfo[childjackid] = {} end
                table.insert(JackpotMgr.getjackpotinfo[childjackid], {  rid = playerdata.rid,
                                                                            rolename = playerdata.rolename,
                                                                            getnum = getoptnum,
                                                                            money_type = EMoneyType.DIAMOND,
                                                                            card_type = playerdata.card_type,
                                                                            table_type = playerdata.table_type,
                                                                            get_time = timetool.get_time()
                                                                        })
                checkgetjackpotinfo(childjackid)
                local logstr = string.format("%d,%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s", EDiamondChange.JACKPOT, playerdata.rid, getoptnum, 
                playerdata.beginvalue, endvalue, childjackid, beforeopen, afteropen, playerdata.card_type, comment.table_uuid, comment.start_time, comment.table_tradeid)
                skynet.send(".jackpotlog", "lua", "jackpot_write_file_redis", logstr, jackpotgameid) 
            end
        end
    end
    if #getjackplayers > 0 then
        -----通知桌子立即更新
        local childjackid = getchildjackid(jackpotconf.childjackopt, playersdata[1].base_score)
        local registertables =  JackpotMgr.register_tableaddress[childjackid]
        if registertables and next(registertables) ~= nil then
            local tableaddress = registertables[table_code]
            if tableaddress and tableaddress > 0 then
                skynet.send(tableaddress, "lua", "updatejackinfo", JackpotMgr.childjackopt_data[childjackid].diamond, EMoneyType.DIAMOND)
            end
        end
    end
    return getjackplayers
end

--[[

message getjackoptrecord {
    required int32 rid = 1;     //玩家rid
    required int32 card_type = 2;  // 玩家牌型
    required string rolename = 3;  // 玩家名称
    required int32 get_value = 4;  // 获得数量
}

//获取彩池相关信息 
message getjackoptinfo {
    
}

message getjackoptinfoR {
    optional int32 jackopt_num = 1; // 彩池总金额
    optional int32 money_type = 2;
    repeated getjackopt getjackopts = 3; // 瓜分比例和牌型
    repeated getjackoptrecord getjackoptrecords = 4; // 奖池瓜分详情
}
--]]
function JackpotMgr.CMD.getjackInfo(base_score)
    local result = {}
    local jackpotconf = getjackpotconf()
    local childjackid = getchildjackid(jackpotconf.childjackopt, base_score)
    local childjackdata = JackpotMgr.childjackopt_data[childjackid]
    if not childjackdata then
        return result
    end
    result.jackopt_num = childjackdata.diamond
    result.money_type = EMoneyType.DIAMOND
    result.getjackopts = {}
    result.getjackoptrecords = {}
    for index, opt in pairs(jackpotconf.getjackopt) do
        table.insert(result.getjackopts, { card_type = index, assignpercent = opt * 100})
    end
    local optrecords = JackpotMgr.getjackpotinfo[childjackid]
    if optrecords ~= nil and next(optrecords) ~= nil then
        for i = #optrecords,1, -1 do
            if #result.getjackoptrecords < 5 then
                local record = optrecords[i]
                table.insert(result.getjackoptrecords, { rid = record.rid, card_type = record.card_type, rolename = record.rolename, get_value = record.getnum })
            else
                break
            end
        end
    end
    return result
end

function JackpotMgr.assignjackopt()
    updatenodeconf(nodeconfname)
    local jackpotconf = getjackpotconf()
    if jackpotconf == nil then return end
    if jackpotconf.childjackopt == nil then return end
    if JackpotMgr.jackopt_data.diamond < 10 then return end
    ----系统先抽成
    local beforeget = JackpotMgr.jackopt_data.diamond
    local sys_get = math.floor( JackpotMgr.jackopt_data.diamond * jackpotconf.system_get)
    local jackopt_get = JackpotMgr.jackopt_data.diamond - sys_get
    JackpotMgr.jackopt_data.diamond = JackpotMgr.jackopt_data.diamond - sys_get
    ----更新到数据库
    cs_jackopt(update_jackpot_all, skynet.getenv("nodename"), -sys_get)
    local logstr = string.format("%d,%d,%d,%d,%d,%d,%s", EDiamondChange.SYS_SUBJACKPOT, 0, sys_get, 
                jackopt_get, beforeget, jackopt_get,  tostring(timetool.get_time()))
    skynet.send(".jackpotlog", "lua", "jackpot_write_file_redis", logstr, jackpotgameid)
    ---记录系统抽成
    local sy_status = cs_jackopt(update_system_get, skynet.getenv("nodename"), sys_get)
    ---再分配到子奖池
    local alldiamond = JackpotMgr.jackopt_data.diamond
    for childjackpotid, jackopt in pairs(jackpotconf.childjackopt) do
        if JackpotMgr.childjackopt_data[childjackpotid] == nil then
            JackpotMgr.childjackopt_data[childjackpotid] = { diamond = 0,}
        end
        local assigndiamond = math.floor(alldiamond *  jackopt.assignpercent)
        if JackpotMgr.jackopt_data.diamond >= assigndiamond then
            local beassign = JackpotMgr.childjackopt_data[childjackpotid].diamond
            local bealljack = JackpotMgr.jackopt_data.diamond
            local status = cs_jackopt(updatejackpotnum, childjackpotid, beassign, assigndiamond)
            if status == true then
                JackpotMgr.childjackopt_data[childjackpotid].diamond = JackpotMgr.childjackopt_data[childjackpotid].diamond + assigndiamond
                JackpotMgr.jackopt_data.diamond = JackpotMgr.jackopt_data.diamond - assigndiamond
                ----更新到数据库
                cs_jackopt(update_jackpot_all, skynet.getenv("nodename"), -assigndiamond)
                local aslogstr = string.format("%d,%d,%d,%d,%d,%d,%d,%d,%s", EDiamondChange.SYS_ASSIGNJACKPOT, 0, childjackpotid, assigndiamond, beassign,
                    JackpotMgr.childjackopt_data[childjackpotid].diamond, bealljack, JackpotMgr.jackopt_data.diamond,  tostring(timetool.get_time()))
                skynet.send(".jackpotlog", "lua", "jackpot_write_file_redis", aslogstr, jackpotgameid)
            end
        end
        ----通知所有注册的桌子更新
        local registertables =  JackpotMgr.register_tableaddress[childjackpotid]
        if registertables and next(registertables) ~= nil then
            for table_code, table_address in pairs(registertables) do
                skynet.send(table_address, "lua", "updatejackinfo", JackpotMgr.childjackopt_data[childjackpotid].diamond, EMoneyType.DIAMOND)
            end
        end
    end
end

function JackpotMgr.CMD.init(nodeconf_name, jackpot_gameid)
    nodeconfname = nodeconf_name
    jackpotgameid = jackpot_gameid
    if nodeconf == nil then
        updatenodeconf(nodeconfname)
    end
    local jackpotconf = getjackpotconf()
    ----从redis拉取牛牛总奖池数据
    JackpotMgr.jackopt_data.diamond = cs_jackopt(get_jackpot_all,skynet.getenv("nodename"))
    for childjackpotid, childconf in ipairs(jackpotconf.childjackopt) do
        if JackpotMgr.childjackopt_data[childjackpotid] == nil then
            JackpotMgr.childjackopt_data[childjackpotid] = { diamond = 0,}
        end
        local childoptnum = cs_jackopt(getjackpotnum, childjackpotid)
        if childoptnum then
            JackpotMgr.childjackopt_data[childjackpotid].diamond = childoptnum
        end
    end
    skynet.fork(function()
        while true do
            ----定时分配
            JackpotMgr.assignjackopt()
            skynet.sleep(10 * 100)
        end
    end)
end

skynet.start(function()
    skynet.dispatch("lua",function(session, source, cmd, ...)
        local f = JackpotMgr.CMD[cmd]
        if f then
            skynet.retpack(f(...))
        else
            skynet.retpack()
        end
    end)
end)